package algo3.algothief.modelo;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;


public class DescripcionDeLadron {

	private String nombre;
	
	private ArrayList<String> sexosPosibles;
	private ArrayList<String> hobbysPosibles;
	private ArrayList<String> cabellosPosibles;
	private ArrayList<String> seniasPosibles;
	private ArrayList<String> vehiculosPosibles;
	
	private HashMap<String, String> caracteristicasElegidas;
		
//-------------------------------------------------------------------------------------
	
	public DescripcionDeLadron() {
		this.nombre = null;
		
		this.caracteristicasElegidas = this.crearCaracteristicasAElegir();
		
		this.sexosPosibles = this.crearSexosPosibles();
		this.hobbysPosibles = this.crearHobbysPosibles();
		this.cabellosPosibles = this.crearCabellosPosibles();
		this.seniasPosibles = this.crearSeniasPosibles();
		this.vehiculosPosibles = this.crearVehiculosPosibles();
	}
	
//-------------------------------------------------------------------------------------
	
	// La descripcion extra es para saber a que pais se refiere dentro del archivo.
	
	// La forma de serializar esta escrita lo mas generica posible.
	public Element serializar(Document doc, String descripcionExtra) {
		Element elementoDescripcion = doc.createElement("DescripcionDeLadron" + descripcionExtra);
		elementoDescripcion.setAttribute("Nombre", this.nombre);
		
		ArrayList<String[]> caracteristicas = this.juntarCaracteristicas();
		int cantidadDeCaracteristicas = caracteristicas.size();
		
		for (int i = 0; i < cantidadDeCaracteristicas; i++) {
			String[] caracteristica = caracteristicas.get(i);
			elementoDescripcion.appendChild(this.agregarCaracteristica(doc,caracteristica));
		}
		
		return elementoDescripcion;
	}
	
	public static DescripcionDeLadron hidratar(Document doc, String descripcionExtra) throws ParserConfigurationException, SAXException, IOException {
		Element elementoDescripcion = (Element)doc.getElementsByTagName("DescripcionDeLadron" + descripcionExtra).item(0);
		boolean descripcionVacia = DescripcionDeLadron.verSiElElementoEstaVacio(elementoDescripcion);
		if (descripcionVacia) return null;
		
		DescripcionDeLadron descripcionNueva = new DescripcionDeLadron();
		
		String nombre = elementoDescripcion.getAttribute("Nombre");
		
		HashMap<String, String> caracteristicas = DescripcionDeLadron.obtenerCaracteristicas(elementoDescripcion);
		DescripcionDeLadron.modificarDatosDeLaDescripcion(descripcionNueva, caracteristicas);
		
		descripcionNueva.definirNombre(nombre);
		
		return descripcionNueva;
	}
	
//-------------------------------------------------------------------------------------
	
	private ArrayList<String[]> juntarCaracteristicas() {
		ArrayList<String[]> caracteristicas = new ArrayList<String[]>();
		
		String[] sexo = { "Sexo", caracteristicasElegidas.get("Sexo") };
		String[] hobby = { "Hobby", caracteristicasElegidas.get("Hobby") };
		String[] cabello = { "Cabello", caracteristicasElegidas.get("Cabello") };
		String[] senia = { "Senia", caracteristicasElegidas.get("Senia") };
		String[] vehiculo = { "Vehiculo", caracteristicasElegidas.get("Vehiculo") };
		
		caracteristicas.add(sexo);
		caracteristicas.add(hobby);
		caracteristicas.add(cabello);
		caracteristicas.add(senia);
		caracteristicas.add(vehiculo);
		
		return caracteristicas;
	}
	
	private Node agregarCaracteristica(Document doc, String[] caracteristica) {
		Element elementoCaracteristica = doc.createElement("Caracteristica");
		elementoCaracteristica.setAttribute(caracteristica[0], caracteristica[1]);
		return elementoCaracteristica;
	}
	
	
	
	private static HashMap<String, String> obtenerCaracteristicas(Element elementoDescripcion) {
		NodeList elementosCaracteristicas = elementoDescripcion.getElementsByTagName("Caracteristica");
		
		String sexo = ((Element)elementosCaracteristicas.item(0)).getAttribute("Sexo");
		String hobby = ((Element)elementosCaracteristicas.item(1)).getAttribute("Hobby");
		String cabello = ((Element)elementosCaracteristicas.item(2)).getAttribute("Cabello");
		String senia = ((Element)elementosCaracteristicas.item(3)).getAttribute("Senia");
		String vehiculo = ((Element)elementosCaracteristicas.item(4)).getAttribute("Vehiculo");
		
		HashMap<String, String> caracteristicas = new HashMap<String, String>();
		
		caracteristicas.put("Sexo",sexo);
		caracteristicas.put("Hobby",hobby);
		caracteristicas.put("Cabello",cabello);
		caracteristicas.put("Senia",senia);
		caracteristicas.put("Vehiculo",vehiculo);
		
		return caracteristicas;
	}
	
	private static void modificarDatosDeLaDescripcion(DescripcionDeLadron descripcion, HashMap<String, String> elecciones) {
		descripcion.seleccionarUnSexo(elecciones.get("Sexo"));
		descripcion.seleccionarUnHobby(elecciones.get("Hobby"));
		descripcion.seleccionarUnCabello(elecciones.get("Cabello"));
		descripcion.seleccionarUnaSenia(elecciones.get("Senia"));
		descripcion.seleccionarUnVehiculo(elecciones.get("Vehiculo"));
	}
	
	private static boolean verSiElElementoEstaVacio(Element elementoDescripcion) {
		int cantidadDeSubElementos = elementoDescripcion.getChildNodes().getLength();
		return (cantidadDeSubElementos == 0);
	}
	
	
	
	private HashMap<String, String> crearCaracteristicasAElegir() {
		HashMap<String, String> caracteristicas = new HashMap<String, String>();
	
		caracteristicas.put("Sexo", null);	
		caracteristicas.put("Hobby", null);
		caracteristicas.put("Cabello", null);
		caracteristicas.put("Senia", null);
		caracteristicas.put("Vehiculo", null);
	
		return caracteristicas;
	}
	
	private ArrayList<String> crearSexosPosibles() {
		ArrayList<String> sexos = new ArrayList<String>();
		
		sexos.add("Femenino");
		sexos.add("Masculino");
		
		return sexos;
	}
	
	private ArrayList<String> crearHobbysPosibles() {
		ArrayList<String> hobbys = new ArrayList<String>();
		
		hobbys.add("Tenis");
		hobbys.add("Musica");
		hobbys.add("Alpinismo");
		hobbys.add("Paracaidismo");
		hobbys.add("Natacion");
		hobbys.add("Croquet");
		
		return hobbys;
	}
	
	private ArrayList<String> crearCabellosPosibles() {
		ArrayList<String> cabellos = new ArrayList<String>();
		
		cabellos.add("Castanio");
		cabellos.add("Rubio");
		cabellos.add("Rojo");
		cabellos.add("Negro");
		
		return cabellos;
	}
	
	private ArrayList<String> crearSeniasPosibles() {
		ArrayList<String> senias = new ArrayList<String>();
		
		senias.add("Anillo");
		senias.add("Tatuaje");
		senias.add("Cicatriz");
		senias.add("Joyas");
		
		return senias;
	}
	
	private ArrayList<String> crearVehiculosPosibles() {
		ArrayList<String> vehiculos = new ArrayList<String>();
		
		vehiculos.add("Descapotable");
		vehiculos.add("Limusina");
		vehiculos.add("Deportivo");
		vehiculos.add("Moto");
		
		return vehiculos;
	}
	
	
	private int buscarIndiceDeLaCaracteristica(ArrayList<String> caracteristicas, String caracteristica) {
		int indiceDeLaCaracteristica = -1;
		int cantidadDeCaracteristicas = caracteristicas.size();
		
		for (int i = 0; ( (indiceDeLaCaracteristica == -1) && (i < cantidadDeCaracteristicas) ); i++) 
			if (caracteristicas.get(i).matches(caracteristica)) 
				indiceDeLaCaracteristica = i;
		
		return indiceDeLaCaracteristica;
	}
	
	// El caso de null esta porque cuando uno no elige ninguna caracteristica
	// particular, te muestran todos los ladrones que puedan llegar a tener
	// una chance de coincidir con el buscado cuando se tengan mas pistas
	private boolean verificaTenerElMismoSexo(String sexo) {
		String sexoElegido = caracteristicasElegidas.get("Sexo");
		return ((sexo == null) || (sexoElegido == null) || (sexoElegido == sexo));
	}
	
	private boolean verificaTenerElMismoHobby(String hobby) {
		String hobbyElegido = caracteristicasElegidas.get("Hobby");
		return ((hobby == null) || (hobbyElegido == null) || (hobbyElegido == hobby));
	}
	
	private boolean verificaTenerElMismoCabello(String cabello) {
		String cabelloElegido = caracteristicasElegidas.get("Cabello");
		return ((cabello == null) || (cabelloElegido == null) || (cabelloElegido == cabello));
	}
	
	private boolean verificaTenerLaMismaSenia(String senia) {
		String seniaElegida = caracteristicasElegidas.get("Senia");
		return ((senia == null) || (seniaElegida == null) || (seniaElegida.matches(senia)));
	}
	
	private boolean verificaTenerElMismoVehiculo(String vehiculo) {
		String vehiculoElegido = caracteristicasElegidas.get("Vehiculo");
		return ((vehiculo == null) || (vehiculoElegido == null) || (vehiculoElegido.matches(vehiculo)));
	}
	
//-------------------------------------------------------------------------------------	
	
	public String verNombre() {
		return this.nombre;
	}
		
	
	public ArrayList<String> verSexosPosibles() {
		return this.sexosPosibles;
	}
		
	public ArrayList<String> verHobbysPosibles() {
		return this.hobbysPosibles;
	}
		
	public ArrayList<String> verCabellosPosibles() {
		return this.cabellosPosibles;
	}
		
	public ArrayList<String> verSeniasPosibles() {
		return this.seniasPosibles;
	}
		
	public ArrayList<String> verVehiculosPosibles() {
		return this.vehiculosPosibles;
	}
	
	
	public void definirNombre(String nombreNuevo) {
		this.nombre = nombreNuevo;
	}
	
	public void seleccionarUnSexo(String sexo) {
		String sexoElegido;
		if (sexo == null) 
			sexoElegido = null;
		else {
			int indice = this.buscarIndiceDeLaCaracteristica(sexosPosibles, sexo);
			if (indice != -1) 
				sexoElegido = sexosPosibles.get(indice);
			else 
				sexoElegido = null;
		}
		caracteristicasElegidas.put("Sexo", sexoElegido);
	}
	
	public void seleccionarUnHobby(String hobby) {
		String hobbyElegido;
		if (hobby == null) 
			hobbyElegido = null;
		else {
			int indice = this.buscarIndiceDeLaCaracteristica(hobbysPosibles, hobby);
			if (indice != -1) 
				hobbyElegido = hobbysPosibles.get(indice);
			else 
				hobbyElegido = null;
		}
		caracteristicasElegidas.put("Hobby", hobbyElegido);
	}
	
	public void seleccionarUnCabello(String cabello) {
		String cabelloElegido;
		if (cabello == null) 
			cabelloElegido = null;
		else {
			int indice = this.buscarIndiceDeLaCaracteristica(cabellosPosibles, cabello);
			if (indice != -1) 
				cabelloElegido = cabellosPosibles.get(indice);
			else 
				cabelloElegido = null;
		}
		caracteristicasElegidas.put("Cabello", cabelloElegido);
	}
	
	public void seleccionarUnaSenia(String senia) {
		String seniaElegida;
		if (senia == null) 
			seniaElegida = null;
		else {
			int indice = this.buscarIndiceDeLaCaracteristica(seniasPosibles, senia);
			if (indice != -1) 
				seniaElegida = seniasPosibles.get(indice);
			else 
				seniaElegida = null;
		}
		caracteristicasElegidas.put("Senia", seniaElegida);
	}
	
	public void seleccionarUnVehiculo(String vehiculo) {
		String vehiculoElegido;
		if (vehiculo == null) 
			vehiculoElegido = null;
		else {
			int indice = this.buscarIndiceDeLaCaracteristica(vehiculosPosibles, vehiculo);
			if (indice != -1) 
				vehiculoElegido = vehiculosPosibles.get(indice);
			else 
				vehiculoElegido = null;
		}
		caracteristicasElegidas.put("Vehiculo", vehiculoElegido);
	}
	
	
	public String verCaracteristica(String nombreDeLaCaracteristica) {
		return caracteristicasElegidas.get(nombreDeLaCaracteristica);
	}
	
	
	public boolean concuerdanLasDescripciones(DescripcionDeLadron otraDescripcion) {
		String sexo = otraDescripcion.verCaracteristica("Sexo");
		String hobby = otraDescripcion.verCaracteristica("Hobby");
		String cabello = otraDescripcion.verCaracteristica("Cabello");
		String senia = otraDescripcion.verCaracteristica("Senia");;
		String vehiculo = otraDescripcion.verCaracteristica("Vehiculo");
		
		boolean mismoSexo = this.verificaTenerElMismoSexo(sexo);
		boolean mismoHobby = this.verificaTenerElMismoHobby(hobby);
		boolean mismoCabello = this.verificaTenerElMismoCabello(cabello);
		boolean mismaSenia = this.verificaTenerLaMismaSenia(senia);
		boolean mismoVehiculo = this.verificaTenerElMismoVehiculo(vehiculo);
		
		return (mismoSexo && mismoHobby && mismoCabello && mismaSenia && mismoVehiculo);
	}
}
